﻿using NationalInstruments.DAQmx;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using 低频天线阵列相控阵信号发生系统SmartFASK12.Models;
using Task = NationalInstruments.DAQmx.Task;

namespace 低频天线阵列相控阵信号发生系统SmartFASK12.Controls
{
    public class MNI2
    {
        public Task myTask = null;
        private static MNI2 _instance = null;

        private MNI2()
        {

        }

        public static MNI2 Singleton()
        {
            if (_instance == null)
            {
                _instance = new MNI2();
            }
            return _instance;
        }

        /// <summary>
        /// 输出电压
        /// </summary>
        /// <returns></returns>
        public string OutputOoltage(ConfigModel2 configModel, double[] Data, SampleQuantityMode continuousSamples, double[] Data2 = null)
        {
            int signalnumber = MConvert.Singleton().KToInt(configModel.signalnumber);
            int samplingrate_modulate = MConvert.Singleton().KToInt(configModel.samplingrate_modulate);
            Cursor.Current = Cursors.WaitCursor;
            try
            {
                string physicalChannel = configModel.physicalChannel;
                if (!string.IsNullOrEmpty(configModel.physicalChannel2))
                {
                    physicalChannel += "," + configModel.physicalChannel2;
                }
                // Create the task and channel
                myTask = new Task();
                myTask.AOChannels.CreateVoltageChannel(physicalChannel,
                    "",
                    configModel.minValue,
                    configModel.maxValue,
                    AOVoltageUnits.Volts);

                // Verify the task before doing the waveform calculations
                myTask.Control(TaskAction.Verify);

                // Calculate some waveform parameters and generate data
                //MFunctionGenerator fGen = new MFunctionGenerator(
                //    myTask.Timing,
                //    configModel.frequency,
                //   configModel.samplesPerBuffer,
                //    configModel.cyclesPerBuffer,
                //   configModel.signalType,
                //    configModel.amplitude);

                // Configure the sample clock with the calculated rate and 
                myTask.Timing.SampleClockRate = samplingrate_modulate;

                // specified clock source
                myTask.Timing.ConfigureSampleClock(System.String.Empty,//clockSourceTextBox.Text 
                                                                       //fGen.ResultingSampleClockRate,
                   samplingrate_modulate,
                    SampleClockActiveEdge.Rising,
                    continuousSamples, signalnumber);

                // Set up the Task Done event

                // Write data to buffer
                //AnalogMultiChannelWriter  writer =
                //    new AnalogSingleChannelWriter(myTask.Stream);

                //writer.WriteMultiSample(false, Data);//fGen.Data
                //writer.WriteMultiSample(false, Data);//fGen.Data
                //writer.WriteWaveform(false, Data);
                // 准备写入数据
                //myTask.WriteAnalogMultiChannel(false, data);

                // 创建AnalogMultiChannelWriter对象

                if (Data2 != null)
                {
                    AnalogMultiChannelWriter writer = new AnalogMultiChannelWriter(myTask.Stream);
                    // 设置数据写入缓冲区
                    double[,] data = new double[2, Data.Length];
                    for (int i = 0; i < Data.Length; i++)
                    {
                        data[0, i] = Data[i];
                        data[1, i] = Data2[i];
                    }
                    // 将数据写入缓冲区
                    writer.WriteMultiSample(false, data);
                }
                else
                {
                    AnalogSingleChannelWriter writer =
                        new AnalogSingleChannelWriter(myTask.Stream);

                    writer.WriteMultiSample(false, Data);//fGen.Data
                }


                myTask.Done += new TaskDoneEventHandler(myTask_Done);
                // Start writing data
                //myTask.Start();

                // Update UI
            }
            catch (DaqException ex)
            {
                Log.Error(ex, ex.Message);
                myTask.Dispose();
                return ex.Message;
            }

            Cursor.Current = Cursors.Default;
            return null;
        }

        /// <summary>
        /// 输出电压
        /// </summary>
        /// <returns></returns>
        public bool OutputOoltage(string physicalChannel, double[,] data, double maxValue, double minValue, double sampleClockRate, int signalnumber, SampleQuantityMode continuousSamples)
        {
            Cursor.Current = Cursors.WaitCursor;
            try
            {
                // Create the task and channel
                myTask = new Task();
                myTask.AOChannels.CreateVoltageChannel(physicalChannel,
                    "",
                    minValue,
                    maxValue,
                    AOVoltageUnits.Volts);

                // Verify the task before doing the waveform calculations
                myTask.Control(TaskAction.Verify);

                // Configure the sample clock with the calculated rate and 
                myTask.Timing.SampleClockRate = sampleClockRate;

                // specified clock source
                myTask.Timing.ConfigureSampleClock(System.String.Empty,//clockSourceTextBox.Text 
                                                                       //fGen.ResultingSampleClockRate,
                   sampleClockRate,
                    SampleClockActiveEdge.Rising,
                    continuousSamples, signalnumber);

                // Set up the Task Done event

                // 创建AnalogMultiChannelWriter对象
                AnalogMultiChannelWriter writer = new AnalogMultiChannelWriter(myTask.Stream);
                // 将数据写入缓冲区
                writer.WriteMultiSample(false, data);

                myTask.Done += new TaskDoneEventHandler(myTask_Done);
                myTask.Start();
                // Update UI

                //return true;
            }
            catch (DaqException ex)
            {
                Log.Error(ex, ex.Message);
                myTask.Dispose();
                return false;
            }

            Cursor.Current = Cursors.Default;
            return true;
        }

        /// <summary>
        /// 电压输出任务完成
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void myTask_Done(object sender, TaskDoneEventArgs e)
        {
            if (myTask != null)
            {
                myTask.Stop();
                myTask.Dispose();
            }

            MEvent.Singleton().EmitVoltageOutputCompleted();
        }

        /// <summary>
        /// 采集电压
        /// </summary>
        /// <param name="configModel"></param>
        /// <returns></returns>
        public double[] CollectVoltage(ConfigModel2 configModel, bool IsManual = false)
        {
            try
            {
                int cyclesPerBuffer_gather = MConvert.Singleton().KToInt(configModel.cyclesPerBuffer_gather) * 3;
                if (IsManual)
                {
                    cyclesPerBuffer_gather = MConvert.Singleton().KToInt(configModel.cyclesPerBuffer_gather);
                }
                int samplesPerBuffer_gather = MConvert.Singleton().KToInt(configModel.samplesPerBuffer_gather);
                //创建采集任务
                using (NationalInstruments.DAQmx.Task myTask = new NationalInstruments.DAQmx.Task())
                {
                    // 创建虚拟通道
                    myTask.AIChannels.CreateVoltageChannel(configModel.physicalChannel_gather, // 物理通道
                                                        "",//物理通道的名称
                                                     configModel.acquisitionCard == 1 ? AITerminalConfiguration.Rse : AITerminalConfiguration.Pseudodifferential,//(AITerminalConfiguration)(-1), // -1表示使用缺省值
                                                        configModel.minValue_gather, // 最小值
                                                        configModel.maxValue_gather,  // 最大值
                                                        AIVoltageUnits.Volts); // 配置时域参数   

                    myTask.Timing.ConfigureSampleClock(System.String.Empty,//外部时钟源线或使用“”作为内部时钟
                                                       samplesPerBuffer_gather, // 外部时钟的预期速率或内部时钟的实际速率
                                                       SampleClockActiveEdge.Rising, //上升或下降边缘获取
                                                       SampleQuantityMode.ContinuousSamples, // 连续或有限样本
                                                       cyclesPerBuffer_gather);// 要获取或用于缓冲区大小（如果连续）的有限样本数
                    // 校验任务
                    myTask.Control(TaskAction.Verify);

                    //多通道读取器，从任务中的一个或多个模拟输入通道读取样本       
                    AnalogMultiChannelReader myAnalogReader = new AnalogMultiChannelReader(myTask.Stream);

                    DateTime t1 = DateTime.Now;

                    double[,] dd = myAnalogReader.ReadMultiSample(cyclesPerBuffer_gather);

                    TimeSpan ts = DateTime.Now - t1;

                    double ms = ts.TotalMilliseconds;

                    if (dd != null && dd.Length > 0)
                    {
                        double[] res = new double[cyclesPerBuffer_gather];
                        for (int i = 0; i < cyclesPerBuffer_gather; i++)
                        {
                            res[i] = dd[0, i];
                        }
                        return res;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
            }
            return null;
        }

        /// <summary>
        /// 输出电压停止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Stop()
        {
            if (myTask != null)
            {
                myTask.Stop();
                myTask.Dispose();
                myTask = null;
            }
        }

        /// <summary>
        /// 获取通道
        /// </summary>
        /// <returns></returns>
        public string[] GetChannals(PhysicalChannelTypes physicalChannelTypes)
        {
            try
            {
                return DaqSystem.Local.GetPhysicalChannels(physicalChannelTypes, PhysicalChannelAccess.External);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message, ex);
            }

            return null;
        }
    }
}
